/*
 *   AS IS License
 * ==Naive Coders==
 */
package org.naive.metawatch.converter;

import java.io.*;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.naive.metawatch.converter.cap.*;
import org.naive.metawatch.converter.parser.cap.CapParseContext;

/**
 *
 * @author gbu.000
 */
public class CapParser {

    private final Map<String, CapComponent> components = new HashMap<>();
    private final CapRawComponent methodComponentBytes;
    private final CapDescriptorComponent descriptorComponent;
    
    public CapParser() {
        descriptorComponent = new CapDescriptorComponent();
        methodComponentBytes = new CapRawComponent();
        
        components.put("Header.cap", new CapHeaderComponent());
        components.put("Directory.cap", new CapDirectoryComponent());
        components.put("Applet.cap", new CapAppletComponent());
        components.put("Import.cap", new CapImportComponent());
        components.put("ConstantPool.cap", new CapConstantPoolComponent());
        components.put("Class.cap", new CapClassComponent());
        components.put("Method.cap", methodComponentBytes);
        components.put("StaticField.cap", new CapStaticFieldComponent());
        components.put("RefLocation.cap", new CapReferenceLocationComponent());
        components.put("Descriptor.cap", descriptorComponent);

    }

    private void parseComponent(InputStream is, ZipEntry ze) throws ParseException, IOException {
        final String componentName = (new File(ze.getName())).getName();
        final CapComponent comp = components.get(componentName);
        if (comp != null) {
            final byte[] data = readAll(is);
            CapParseContext cpc = new CapParseContext(data);
            comp.parse(cpc);
            System.out.println(comp);
        }
    }

    private static byte[] readAll(InputStream is) throws IOException {
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            byte[] kilo = new byte[1024];
            int read;
            while ((read = is.read(kilo)) > 0) {
                bos.write(kilo, 0, read);
            }
        } finally {
            bos.close();
        }
        return bos.toByteArray();
    }

    public void readCap(String sCapFileName)
            throws FileNotFoundException, IOException, ParseException {
        try (ZipInputStream zin = new ZipInputStream(new FileInputStream(sCapFileName))) {
            ZipEntry zEntry;

            while ((zEntry = zin.getNextEntry()) != null) {

                if (!zEntry.isDirectory()) {
                    parseComponent(zin, zEntry);
                }
            }
            // second pass
            final CapParseContext px = new CapParseContext(methodComponentBytes.bytes);
            final CapMethodComponent mc = new CapMethodComponent(descriptorComponent.classes);
            mc.parse(px);
            System.out.println(mc);
        }
    }
}
